home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / minix / update~4.z / update~4 / lib_stdio_scanf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-09-06  |  9.0 KB  |  452 lines

  1. /* scanf - formatted input conversion    Author: Patrick van Kleef */
  2.  
  3. #define __SRC__
  4.  
  5. /*
  6.  * - added %f,%e,%g
  7.  * - [scanset] implementation wrote into format string, which is 
  8.  *   obviously a no-no. Changed that real quick.
  9.  * - added [0-9] style scansets
  10.  *    ++jrb bammi@dsrgsun.ces.cwru.edu
  11.  *
  12.  * 12/10/88 minor bugfix to accept floating #'s of the for .nnnn
  13.  *    ++jrb
  14.  */
  15.  
  16.  
  17. #include <stdio.h>
  18.  
  19.  
  20. int scanf (format, args)
  21. CONST char    *format;
  22. int         args;
  23. {
  24.     return _doscanf (0, stdin, format, &args);
  25. }
  26.  
  27.  
  28.  
  29. int fscanf (fp, format, args)
  30. FILE        *fp;
  31. CONST char    *format;
  32. int        args;
  33. {
  34.     return _doscanf (0, fp, format, &args);
  35. }
  36.  
  37.  
  38. int sscanf (string, format, args)
  39. CONST char    *string;        /* source of data */
  40. CONST char    *format;        /* control string */
  41. int        args;
  42. {
  43.     return _doscanf (1, string, format, &args);
  44. }
  45.  
  46. union ptr_union {
  47.     char           *chr_p;
  48.     unsigned int   *uint_p;
  49.     unsigned long  *ulong_p;
  50. #ifndef __NO_FLOATS__
  51.     float           *float_p;
  52.     double           *double_p;
  53. #endif
  54. };
  55.  
  56. static int      ic;        /* the current character */
  57. static char    *rnc_arg;    /* the string or the filepointer */
  58. static int      rnc_code;    /* 1 = read from string, else from FILE */
  59.  
  60. /* get the next character */
  61.  
  62. static void rnc ()
  63. {
  64.     if (rnc_code) {
  65.     if (!(ic = *rnc_arg++))
  66.         ic = EOF;
  67.     } else
  68.     ic = getc ((FILE *) rnc_arg);
  69. }
  70.  
  71. /*
  72.  * unget the current character 
  73.  */
  74.  
  75. static void ugc ()
  76. {
  77.     
  78.     if (rnc_code)
  79.     --rnc_arg;
  80.     else
  81.     ungetc (ic, (FILE *)rnc_arg);
  82. }
  83.  
  84. /* [01234] style scanset */
  85. static int scn1index(ch, string, endmarker)
  86. char ch;
  87. char *string, *endmarker;
  88. {
  89.     while (*string++ != ch) 
  90.     if (string >= endmarker)
  91.         return 0;
  92.     return 1;
  93. }
  94.  
  95. static int scnindex(ch, string, endmarker)
  96. char ch;
  97. char *string, *endmarker;
  98. {
  99.     if(((endmarker - string) == 3) && (string[1] == '-'))
  100.     /* [0-9] style scanset */
  101.     return ((string[0] <= ch) &&  (ch <= string[2]));
  102.     else
  103.     return scn1index(ch, string, endmarker);
  104. }
  105.  
  106. /*
  107.  * this is cheaper than iswhite from <ctype.h> 
  108.  */
  109.  
  110. static int iswhite (ch)
  111. int             ch;
  112. {
  113.     return (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
  114. }
  115.  
  116. static int isdigit (ch)
  117. int             ch;
  118. {
  119.     return (ch >= '0' && ch <= '9');
  120. }
  121.  
  122. static int __tolower (ch)
  123. int             ch;
  124. {
  125.     if (ch >= 'A' && ch <= 'Z')
  126.     ch = ch + 'a' - 'A';
  127.     
  128.     return ch;
  129. }
  130.  
  131. #ifndef __NO_FLOATS__
  132. #ifdef __GNUC__
  133. /* eval f * 10**p */
  134. static double _fraise(f, p)
  135. double f;
  136. int p;
  137. {
  138.     if(p > 0)
  139.     while(p--)
  140.         f *= 10.0;
  141.     else
  142.     while(p++)
  143.         f /= 10.0;
  144.     return f;
  145. }
  146. #endif
  147. #endif
  148.  
  149. /*
  150.  * the routine that does the job 
  151.  */
  152.  
  153. int _doscanf (code, funcarg, format, argp)
  154. int             code;        /* function to get a character */
  155. char           *funcarg;    /* an argument for the function */
  156. char           *format;        /* the format control string */
  157. union ptr_union *argp;        /* our argument list */
  158. {
  159.     int             done = 0;    /* number of items done */
  160.     int             base;        /* conversion base */
  161.     long            val;        /* an integer value */
  162.     int             sign;        /* sign flag */
  163.     int             do_assign;    /* assignment suppression flag */
  164.     unsigned        width;        /* width of field */
  165.     int             widflag;    /* width was specified */
  166.     int             longflag;    /* true if long */
  167.     int             done_some;    /* true if we have seen some data */
  168.     int        reverse;    /* reverse the checking in [...] */
  169.     char           *endbracket;     /* position of the ] in format string */
  170. #ifndef __NO_FLOATS__
  171. #ifdef __GNUC__
  172.     double        fval;        /* a double value  */
  173. #endif
  174. #endif
  175.     
  176.     
  177.     rnc_arg = funcarg;
  178.     rnc_code = code;
  179.     
  180.     rnc ();            /* read the next character */
  181.     
  182.     if (ic == EOF) {
  183.     done = EOF;
  184.     goto quit;
  185.     }
  186.     
  187.     while (1) {
  188.     while (iswhite (*format))
  189.         ++format;    /* skip whitespace */
  190.     if (!*format)
  191.         goto all_done;    /* end of format */
  192.     if (ic < 0)
  193.         goto quit;    /* seen an error */
  194.     if (*format != '%') {
  195.         while (iswhite (ic))
  196.         rnc ();
  197.         if (ic != *format)
  198.         goto all_done;
  199.         ++format;
  200.         rnc ();
  201.         ++done;
  202.         continue;
  203.     }
  204.     ++format;
  205.     do_assign = 1;
  206.     if (*format == '*') {
  207.         ++format;
  208.         do_assign = 0;
  209.     }
  210.     if (isdigit (*format)) {
  211.         widflag = 1;
  212.         for (width = 0; isdigit (*format);)
  213.         width = width * 10 + *format++ - '0';
  214.     } else
  215.         widflag = 0;    /* no width spec */
  216.     if (longflag = (__tolower (*format) == 'l'))
  217.         ++format;
  218.     if (*format != 'c')
  219.         while (iswhite (ic))
  220.         rnc ();
  221.     done_some = 0;    /* nothing yet */
  222.     switch (*format) {
  223.       case 'o':
  224.         base = 8;
  225.         goto decimal;
  226.       case 'u':
  227.       case 'd':
  228.         base = 10;
  229.         goto decimal;
  230.       case 'x':
  231.         base = 16;
  232.         if (((!widflag) || width >= 2) && ic == '0') {
  233.         rnc ();
  234.         if (__tolower (ic) == 'x') {
  235.             width -= 2;
  236.             done_some = 1;
  237.             rnc ();
  238.         } else {
  239.             ugc ();
  240.             ic = '0';
  241.         }
  242.         }
  243.       decimal:
  244.         val = 0L;    /* our result value */
  245.         sign = 0;    /* assume positive */
  246.         if (!widflag)
  247.         width = 0xffff;    /* very wide */
  248.         if (width && ic == '+')
  249.         rnc ();
  250.         else if (width && ic == '-') {
  251.         sign = 1;
  252.         rnc ();
  253.         }
  254.         while (width--) {
  255.         if (isdigit (ic) && ic - '0' < base)
  256.             ic -= '0';
  257.         else if (base == 16 && __tolower (ic) >= 'a' && __tolower (ic) <= 'f')
  258.             ic = 10 + __tolower (ic) - 'a';
  259.         else
  260.             break;
  261.         val = val * base + ic;
  262.         rnc ();
  263.         done_some = 1;
  264.         }
  265.         if (do_assign) {
  266.         if (sign)
  267.             val = -val;
  268.         if (longflag)
  269.             *(argp++)->ulong_p = (unsigned long) val;
  270.         else
  271.             *(argp++)->uint_p = (unsigned) val;
  272.         }
  273.         if (done_some)
  274.         ++done;
  275.         else
  276.         goto all_done;
  277.         break;
  278.       case 'c':
  279.         if (!widflag)
  280.         width = 1;
  281.         while (width-- && ic >= 0) {
  282.         if (do_assign)
  283.             *(argp)->chr_p++ = (char) ic;
  284.         rnc ();
  285.         done_some = 1;
  286.         }
  287.         if (do_assign)
  288.         argp++;    /* done with this one */
  289.         if (done_some)
  290.         ++done;
  291.         break;
  292.       case 's':
  293.         if (!widflag)
  294.         width = 0xffff;
  295.         while (width-- && !iswhite (ic) && ic > 0) {
  296.         if (do_assign)
  297.             *(argp)->chr_p++ = (char) ic;
  298.         rnc ();
  299.         done_some = 1;
  300.         }
  301.         if (do_assign)        /* terminate the string */
  302.         *(argp++)->chr_p = '\0';    
  303.         if (done_some)
  304.         ++done;
  305.         else
  306.         goto all_done;
  307.         break;
  308.         
  309. #ifndef __NO_FLOATS__
  310. #ifdef __GNUC__
  311.       case 'e':
  312.       case 'f':
  313.       case 'g':
  314.         fval = 0.0;    /* our result value */
  315.         sign = 0;    /* assume positive */
  316.         if (!widflag)
  317.         width = 0xffff;    /* very wide */
  318.         if (width && ic == '+')
  319.         rnc ();
  320.         else if (width && ic == '-') {
  321.         sign = 1;
  322.         rnc ();
  323.         }
  324.         while (width && isdigit(ic)) {
  325.         width--;
  326.         fval = fval * 10.0 + (ic - '0');
  327.         rnc ();
  328.         done_some = 1;
  329.         }
  330.         if(ic == '.')
  331.         {
  332.         double factor = 1.0/10.0;
  333.         rnc ();
  334.         while (--width && isdigit(ic))
  335.         {
  336.             fval = fval + ((ic - '0') * factor);
  337.             factor = factor/10.0;
  338.             done_some = 1;
  339.             rnc();
  340.         }
  341.         }
  342.         if(sign)
  343.         fval = -fval;
  344.         sign = 0;
  345.         if(((ic == 'E') || (ic == 'e')) && done_some)
  346.         {
  347.         int pow = 0;
  348.         rnc ();
  349.         if((ic == '+') || (ic == '-'))
  350.         {
  351.             if(ic == '-') sign = 1;
  352.             width--;
  353.             rnc();
  354.         } 
  355.         
  356.         while(--width && isdigit(ic))
  357.         {
  358.             pow = pow * 10 + (ic -'0');
  359.             rnc();
  360.         }
  361.         fval = _fraise(fval, (sign == 1)? -pow : pow);
  362.         }
  363.         if (do_assign) {
  364.         if (longflag)
  365.             *(argp++)->double_p = fval;
  366.         else
  367.             *(argp++)->float_p = (float) fval;
  368.         }
  369.         if (done_some)
  370.         ++done;
  371.         else
  372.         goto all_done;
  373.         break;
  374. #endif /* __GNUC__ */
  375. #endif /* __NO_FLOATS__ */
  376.  
  377.       case '[':
  378.         if (!widflag)
  379.         width = 0xffff;
  380.         
  381.         if ( *(++format) == '^' ) {
  382.         reverse = 1;
  383.         format++;
  384.         } else
  385.         reverse = 0;
  386.         
  387.         endbracket = format;
  388.         while ( *endbracket != ']'  && *endbracket != '\0')
  389.         endbracket++;
  390.         
  391.         if (!*endbracket)
  392.         goto quit;
  393.         
  394.         while (width-- && !iswhite (ic) && ic > 0 && 
  395.            (scnindex(ic, format, endbracket) ^ reverse)) {
  396.         if (do_assign)
  397.             *(argp)->chr_p++ = (char) ic;
  398.         rnc ();
  399.         done_some = 1;
  400.         }
  401.         
  402.         if (do_assign)        /* terminate the string */
  403.         *(argp++)->chr_p = '\0';    
  404.         if (done_some)
  405.         ++done;
  406.         else
  407.         goto all_done;
  408.         break;
  409.     }        /* end switch */
  410.     ++format;
  411.     }
  412.   all_done:
  413.     if (ic >= 0)
  414.     ugc ();        /* restore the character */
  415.   quit:
  416.     return done;
  417. }
  418.  
  419. #if 0
  420. /* TEST ONLY */
  421. main()
  422. {
  423.     int i, n;
  424.     float x;
  425.     char name[50];
  426.  
  427.     n = scanf("%d%f%s", &i, &x, name);
  428.     printf("n = %d i = %d x = %f name = :%s:\n", n, i, x, name);
  429.     /* input:  54.32E-1 thompson */
  430.     /* output: n = 3 i = 25 x = 5.432000 name = :thompson: */
  431.     
  432.     n = scanf("%2d%f%*d %[0-9]", &i, &x, name);
  433.     printf("n = %d i = %d x = %f name = :%s:\n", n, i, x, name);
  434.     /* input:  56789 0123 56a72 */
  435.     /* output: n = 4 i = 56 x = 789.000000 name = :56: */
  436.  
  437.     n = scanf("%s", name);
  438.     printf("n = %d name = :%s:\n", n, name);
  439.     /* output: n = 1 name = :a72: */
  440.  
  441.     n = scanf("%2d%f%*d %[0123456789]", &i, &x, name);
  442.     printf("n = %d i = %d x = %f name = :%s:\n", n, i, x, name);
  443.     /* input:  56789 0123 56a72 */
  444.     /* output: n = 4 i = 56 x = 789.000000 name = :56: */
  445.     /* 'a72' left over */
  446.  
  447.     n = scanf("%s", name);
  448.     printf("n = %d name = :%s:\n", n, name);
  449.     /* output: n = 1 name = :a72: */
  450. }
  451. #endif /* test only */
  452.